﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Neoit.Utils.TemplateParser
{
    /// <summary>
    /// Parse List: 'item in list'
    /// </summary>
    public class ParseList
    {
        /* eg: <list $='item in list.xx'> </list>
         * 多于的</list>不解析、多余的<list $='item in list.xx'>若匹配不到则不解析
         * 不存在的集合按空处理
         * 属性不区分大小写
         */
        /// <summary>
        /// StartTagPattern
        /// </summary>
        public const string StartTagPattern = @"<list\s+\$='(.*?)'>";
        /// <summary>
        /// EndTagPattern
        /// </summary>
        public const string EndTagPattern = @"</list>";
        /// <summary>
        /// Parse
        /// </summary>
        public static string Parse<T>(string template, T data)
        {
            //template = ParseCommon.AdjustLabelLine(template, StartTagPattern, EndTagPattern);
            template = ParseTemplate(template, data);
            return template;
        }

        private static string ParseTemplate(string template, object data)
        {
            var stack = new Stack<Match>();
            var regex = new Regex($"{StartTagPattern}|{EndTagPattern}", RegexOptions.Singleline);
            var matches = regex.Matches(template);

            var deep = 0;
            foreach (Match match in matches)
            {
                if (match.Value != EndTagPattern)//startTag
                {
                    stack.Push(match);
                }
                else//endTag
                {
                    deep++;
                    if (stack.Count == 0) continue;
                    stack.Pop();
                    if (stack.Count == 0)
                    {
                        var pattern = $"{StartTagPattern}({ParseCommon.JoinString(Enumerable.Repeat(EndTagPattern, deep - 1).Select(s => ".*?" + s))}.*?){EndTagPattern}";
                        var _match = Regex.Match(template, pattern, RegexOptions.Singleline);
                        var expression = _match.Groups[1];//item in list.tags
                        var innerContent = _match.Groups[2].Value;//item in list.tags

                        var forEachString = Regex.Match(expression.Value, @"(.+)\s+in\s+(.+)", RegexOptions.Singleline);
                        var itemName = forEachString.Groups[1].Value;
                        var listName = forEachString.Groups[2].Value;
                        var count = Convert.ToInt32(ParseCommon.GetValueByPath(data, $"{listName}.Count"));
                        if (count == 0)
                        {
                            template = RegexReplaceFirst(template, pattern, "");
                        }
                        else
                        {
                            var _inner = "";
                            for (int i = 0; i < count; i++)
                            {
                                _inner += Regex.Replace(innerContent, $@"\${{{itemName}\.", $"${{{listName}[{i}]."); // case1: {item.name}
                                _inner = Regex.Replace(_inner, @"<list [^>]*>(.*?)", (Match m) => // case2: <list $='item2 in item.list2'>
                                {
                                    return m.Value.Replace($"{itemName}.", $"{listName}[{i}].");
                                });
                                //@"item\.(?=[^\""]*\""(?:[^\""]*\""[^\""]*\"")*[^\""]*$)"
                                //@"<if [^>]*>(.*?)"
                                _inner = Regex.Replace(_inner, @"<if [^>]*>(.*?)", (Match m) => // case3: <if $='item.name=="xx"'>
                                {
                                    return m.Value.Replace($"{itemName}.", $"{listName}[{i}].");
                                });
                            }
                            template = template.Substring(0, _match.Index) + _inner + template.Substring(match.Index + match.Length);
                        }
                        if (matches.ToList().IndexOf(match) < matches.Count - 1)
                        {
                            return ParseTemplate(template, data);
                        }
                        deep = 0;
                    }
                }
            }
            return template;
        }


        private static string RegexReplaceFirst(string input, string pattern, string replacement)
        {
            bool replaced = false;
            string result = Regex.Replace(input, pattern, m =>
            {
                if (!replaced)
                {
                    replaced = true;
                    return replacement;
                }
                return m.Value;
            }, RegexOptions.Singleline);
            return result;
        }
    }
}
